package org.goj.user.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.goj.common.constant.RedisConstant;
import org.goj.common.constant.ResultCode;
import org.goj.common.entity.user.User;
import org.goj.common.entity.user.UserRole;
import org.goj.common.model.RequestUtil;
import org.goj.common.model.Result;
import org.goj.feign.feign.BaseFeignClient;
import org.goj.user.mapper.UserMapper;
import org.goj.user.mapper.UserRoleMapper;
import org.goj.user.service.UserService;
import org.goj.user.vo.PersonClassify;
import org.goj.user.vo.PersonClassifyVO;
import org.goj.user.vo.PersonInfo;
import org.goj.user.vo.PersonRecord;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author CK
 * @since 2020-12-02
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private RedisTemplate<Object, Object> redisTemplate;

    @Resource
    private BCryptPasswordEncoder passwordEncoder;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertUserAndUserRole(String email, String password) {
        User user = new User();
        user.setEmail(email).setPassword(passwordEncoder.encode(password)).setDefunct("N").setIp(RequestUtil.request().getRemoteAddr())
                .setRegTime(new Date()).setAccessTime(new Date()).setNick("未命名")
                .setHeadPortrait("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif?imageView2/1/w/80/h/80");
        int f = userMapper.saveGetId(user);
        Assert.isTrue(f == 1, "添加用户失败！");
        UserRole userRole = new UserRole();
        //注册为普通用户
        userRole.setRoleId(2);
        userRole.setUserId(user.getUserId());
        int a = userRoleMapper.insert(userRole);
        Assert.isTrue(a == 1, "添加用户失败！");
        return true;
    }

    @Override
    public PersonClassifyVO personClassify(Integer userId) {
        List<PersonClassify> personClassify = userMapper.personClassify(userId);
        for (int i = personClassify.size(); i < 3; i++) {
            PersonClassify p = new PersonClassify();
            p.setValue(0);
            p.setName("NULL" + i);
            personClassify.add(p);
        }
        PersonClassifyVO personClassifyVO = new PersonClassifyVO();
        personClassifyVO.setDatas(personClassify);
        personClassifyVO.setData(personClassify.stream().map(
                PersonClassify::getName).collect(Collectors.toList()));
        return personClassifyVO;
    }

    @Override
    public Page<PersonRecord> personRecord(Integer userId, Integer current, Integer size) {
        Page<PersonRecord> page = new Page<>(current, size);
        return userMapper.personRecord(page, userId);
    }

    @Override
    public PersonInfo personInfo(Integer userId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("nick", "sex", "reg_time", "description", "school", "clbum", "number").eq("user_id", userId);
        User user = userMapper.selectOne(queryWrapper);
        PersonInfo personInfo = new PersonInfo();
        BeanUtils.copyProperties(user, personInfo);
        return personInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean baseInfo(Integer userId, Integer sex, String nick, String description) {
        User user = new User();
        user.setUserId(userId).setSex(sex).setNick(nick).setDescription(description);
        int flag = userMapper.updateById(user);
        Assert.isTrue(flag == 1, "更新用户基本信息失败");
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String uploadImage(BaseFeignClient baseFeignClient, Integer userId, MultipartFile image) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("head_portrait").eq("user_id", userId);
        User userHead = userMapper.selectOne(queryWrapper);
        Result<String> result = baseFeignClient.upload(image);
        Assert.isTrue(result.getCode().equals(ResultCode.SUCCESS.getCode()), "更新头像失败");
        User user = new User();
        user.setUserId(userId).setHeadPortrait(result.getData());
        int flag = userMapper.updateById(user);
        Assert.isTrue(flag == 1, "更新头像失败");
        try {
            baseFeignClient.delete(userHead.getHeadPortrait());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.getData();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean schoolInfo(Integer userId, String school, String clbum, String number) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_id").eq("number", number);
        Assert.isTrue(userMapper.selectCount(queryWrapper) < 1, "此学号已经存在");
        User user = new User();
        user.setUserId(userId).setSchool(school).setClbum(clbum).setNumber(number);
        int flag = userMapper.updateById(user);
        Assert.isTrue(flag == 1, "更新学校信息失败");
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateEmail(Integer userId, String password, String email, String code) {
        String redisCode = (String) redisTemplate.opsForValue().get(RedisConstant.EMAIL_VALIDATE_CODE + email);
        Assert.notNull(redisCode, "验证码不存在或已过期！");
        Assert.isTrue(redisCode.equals(code), "验证码输入错误！");
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        List<User> user = userMapper.selectList(queryWrapper);
        Assert.isTrue(user.size() == 0, "该邮箱已经被使用！");
        QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.select("password").eq("user_id", userId);
        User user2 = userMapper.selectOne(queryWrapper2);
        boolean flag = passwordEncoder.matches(password, user2.getPassword());
        Assert.isTrue(flag, "密码验证失败！");
        User user3 = new User();
        user3.setEmail(email).setUserId(userId);
        int flag2 = userMapper.updateById(user3);
        Assert.isTrue(flag2 == 1, "更新邮箱失败！");
        redisTemplate.delete(RedisConstant.EMAIL_VALIDATE_CODE + email);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePassword(Integer userId, String password, String newPass, String rePass, String email, String code) {
        Assert.isTrue(newPass.equals(rePass) && StrUtil.isNotBlank(newPass), "两次输入密码不相等！");
        String redisCode = (String) redisTemplate.opsForValue().get(RedisConstant.EMAIL_VALIDATE_CODE + email);
        Assert.notNull(redisCode, "验证码不存在或已过期！");
        Assert.isTrue(redisCode.equals(code), "验证码输入错误！");
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("password").eq("user_id", userId);
        User user2 = userMapper.selectOne(queryWrapper);
        boolean flag = passwordEncoder.matches(password, user2.getPassword());
        Assert.isTrue(flag, "原密码输入错误！");
        User user = new User();
        user.setPassword(passwordEncoder.encode(newPass)).setUserId(userId);
        int flag2 = userMapper.updateById(user);
        Assert.isTrue(flag2 == 1, "修改密码失败！");
        redisTemplate.delete(RedisConstant.EMAIL_VALIDATE_CODE + email);
        return true;
    }

    @Override
    public Page<User> userList(String name, String defunct, String startDate, String endDate, Integer current, Integer size) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_id", "nick", "email", "sex", "clbum", "number", "ip", "reg_time", "defunct")
                .and(StrUtil.isNotBlank(name),
                        t -> t.like("nick", name).or().like("clbum", name).or().like("number", name))
                .eq(StrUtil.isNotBlank(defunct), "defunct", defunct)
                .between(StrUtil.isNotBlank(startDate) && StrUtil.isNotBlank(endDate),
                        "reg_time", startDate, endDate)
                .orderByDesc("reg_time");
        Page<User> page = new Page<>(current, size);
        return super.page(page, queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean insertUser(String email, String password, String defunct, String nick, Integer sex, Integer roleId, String clbum, String number) {
        User user = new User();
        user.setEmail(email).setPassword(passwordEncoder.encode(password)).setDefunct(defunct)
                .setIp(RequestUtil.request().getRemoteAddr()).setSex(sex)
                .setRegTime(new Date()).setAccessTime(new Date())
                .setHeadPortrait("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif?imageView2/1/w/80/h/80");
        if (StrUtil.isNotBlank(nick)) {
            user.setNick(nick);
        } else {
            user.setNick("未命名");
        }
        if (StrUtil.isNotBlank(clbum)) {
            user.setClbum(clbum);
        }
        if (StrUtil.isNotBlank(number)) {
            user.setNumber(number);
        }
        int f = userMapper.insertUser(user);
        Assert.isTrue(f == 1, "添加用户失败");
        UserRole userRole = new UserRole();
        userRole.setRoleId(roleId);
        userRole.setUserId(user.getUserId());
        int a = userRoleMapper.insert(userRole);
        Assert.isTrue(a == 1, "添加用户失败！");
        return true;
    }
}
